
#ifndef __CONFIG__H__
#define __CONFIG__H__
#include<iostream>
#include<memory>
#include<sstream>
#include<boost/lexical_cast.hpp>
#include"Log.h"
#include<map>
#include<yaml-cpp/yaml.h>
#include<functional>
#include"mutex.h"
#include "thread.h"
namespace Yizhi
{
    //基类
    class ConfigVarbase{
        public:
        //智能指针
        typedef std::shared_ptr<ConfigVarbase> ptr;

        //构造函数
        ConfigVarbase(const std::string& name="",const std::string &desription="")
        :m_name(name)
        ,m_desription(desription){
            //将m_name进行小写转换，使其大小写不敏感
            std::transform(m_name.begin(),m_name.end(),m_name.begin(),::tolower);
        }

        //虚构函数
        virtual ~ConfigVarbase(){} 

        //将value转换成字符串
        virtual std::string Tostirng()=0;

        //从字符串中提取value
        virtual bool Fromstring(const std::string &value)=0;


        std::string getname(){return m_name;}
        std::string getdesription(){return m_desription;}

        
        private:
        std::string m_name;
        std::string m_desription;
    };
    


    //模板函数实现基础类型的序列化和反序列化
    template<class F,class T>
    class Lexical_cast{
        public:
        T operator()(const F &v){
            return boost::lexical_cast<T>(v);
        }
    };

    //vector序列化，Lexical_cast片特化
    template<class T>
    class Lexical_cast<std::vector<T>,std::string>{
        public:
        std::string operator()(const std::vector<T> &vec){
            YAML::Node node;
            static Lexical_cast<T,std::string> converter;
            for(auto const &i:vec){
                node.push_back(YAML::Load(converter(i)));//从值转换成string后，加载为Yaml::Node类型
            }
            std::stringstream ss;
            ss<<node;
            return ss.str();
        }
    };

    //vector反序列化，Lexical_cast片特化
    template<class T>
    class Lexical_cast<std::string,std::vector<T>>{
        public:
        std::vector<T> operator()(const std::string &str){
            YAML::Node node=YAML::Load(str);
            std::vector<T> vec;
            static Lexical_cast<std::string,T> converter;
            for(auto const &i:node){
                vec.push_back(converter(i.as<std::string>()));//从yaml::node类型转换成值
            }
            return vec;
        }
    };

    //map序列化，Lexical_cast片特化
    template<class T>
    class Lexical_cast<std::map<std::string,T>,std::string>{
        public:
        std::string operator()(const std::map<std::string,T> &map){
            YAML::Node node;
            static Lexical_cast<T,std::string> value_converter;
            for(auto const &i:map){
                node[i.first]=value_converter(i.second);    
            }
            std::stringstream ss;
            ss<<node;
            return ss.str();
        }
    };
    //map反序列化，Lexical_cast片特化
    template<class T>
    class Lexical_cast<std::string,std::map<std::string,T>>{
        public:
        std::map<std::string,T> operator()(const std::string &str){
            YAML::Node node=YAML::Load(str);
            std::map<std::string,T> map;
            static Lexical_cast<std::string,T> value_converter;            
            for(auto const &i:node){
                map[i.first.as<std::string>()]=value_converter(i.second.as<std::string>());   
                }
            return map;
        }
    }; 

    //set序列化
    template<class T>
    class Lexical_cast<std::set<T>,std::string>{
        public:
        std::string operator()(const std::set<T> &set){
            YAML::Node node;
            static Lexical_cast<T,std::string> value_converter;
            for(auto &it:set){
                node.push_back(value_converter(it));
            }
            std::stringstream ss;
            ss<<node;
            return ss.str();
        } 
    };


    //set反序列化
    template<class T>
    class Lexical_cast<std::string, std::set<T>>{
        public:
        std::set<T> operator()(const std::string& str){
            YAML::Node node=YAML::Load(str);
            std::set<T> res;
            static Lexical_cast<std::string, T> value_converter;
            std::stringstream ss;
            for(size_t i=0;i<node.size();i++){
                ss.str("");
                ss<<node[i];
                res.insert(value_converter(ss.str()));
            }
            return res;
        }
    };



    //子类，实现基础类型的序列化和反序列化
    template<class T,class Fromstr=Lexical_cast<std::string,T>,class Tostr=Lexical_cast<T,std::string>>
    class ConfigVar:public ConfigVarbase{
        public:
        typedef RWMutex MutexType;
        typedef std::shared_ptr<ConfigVar> ptr;
        typedef std::function<void(const T&old_value,const T&new_value)>on_change_cb;

        ConfigVar(const std::string &name,const T& default_val,const std::string &desription="")
        :ConfigVarbase(name,desription),val(default_val){
        }
        std::string Tostirng() override{
            try{
                //return boost::lexical_cast<std::string>(val);
                MutexType::ReadLock rlock(m_mutex);
                return Tostr()(val);
            }catch(std::exception &e){
                SERVER_LOG_ERROR(SERVER_LOG_ROOT())<<"Configvar::Tostring exception"<<e.what()
                <<"Convert"<<typeid(val).name()<<"To string";
            }
            return "";
        }
        bool Fromstring (const std::string &value) override{
            try{
               // val=boost::lexical_cast<T>(value);
                setvalue(Fromstr()(value));
                return true;
            }
            catch(std::exception &e){
                SERVER_LOG_ERROR(SERVER_LOG_ROOT())<<"ConfigVar::Fromstring exception"<<e.what()
                <<"Convert From String to"<<typeid(val).name();
            }
            return false;
        }
        T getvalue()
        {   
            MutexType::ReadLock rlock(m_mutex);
            return val;
        }
        void setvalue(T value)
        {   
            MutexType::WriteLock wlock(m_mutex);
            if(val==value){
                return;
            }
            for (auto it=m_cbs.begin();it!=m_cbs.end();it++)
            {
                it->second(val,value);
            }
        
            val=value;
        }
        uint64_t addListener(on_change_cb cb){
            static uint64_t key=0;
            MutexType::WriteLock wrlock(m_mutex);
            key++;
            m_cbs[key]=cb;
            return key;
          
        
        }
        void delListener(uint64_t key){
            MutexType::WriteLock wrlock(m_mutex);
            m_cbs.erase(key);
        }
        void clearListener(){
            MutexType::WriteLock wrlock(m_mutex);
            m_cbs.clear();
        }
        private:
        MutexType m_mutex;
        std::map<uint64_t,on_change_cb> m_cbs;
        T val;
    };
    class Config {
    public:
    typedef std::map<std::string,Yizhi::ConfigVarbase::ptr> ConfigVarMap;
    typedef RWMutex MutexType;
    template<class T>
    static typename ConfigVar<T>::ptr Lookup(const std::string& name,
            const T& default_value, const std::string& description = "") {
            MutexType::WriteLock wlock(GetMutex());
            auto it = Getdatas().find(name);
            if(it!=Getdatas().end()){
                auto tmp = std::dynamic_pointer_cast<ConfigVar<T> >(it->second);
                if(tmp) {
                    SERVER_LOG_INFO(SERVER_LOG_ROOT()) << "Lookup name=" << name << " exists";
                    return tmp;
                }
                else{
                    SERVER_LOG_INFO(SERVER_LOG_ROOT())<<"Lookup name exit but type not";
                    return nullptr; 
                }
                
               
            }

            if(name.find_first_not_of("abcdefghikjlmnopqrstuvwxyz._0123456789")
            != std::string::npos) {
                  SERVER_LOG_ERROR(SERVER_LOG_ROOT()) << "Lookup name invalid " << name;
                  throw std::invalid_argument(name);
            }
            


            typename ConfigVar<T>::ptr v(new ConfigVar<T>(name, default_value, description));
            Getdatas()[name] = v;
            return v;
    }

    template<class T>
    static typename ConfigVar<T>::ptr Lookup(const std::string& name) {
        MutexType::ReadLock rlock(GetMutex());
        auto it = Getdatas().find(name);
        if(it == Getdatas().end()) {
            return nullptr;
        }
        return std::dynamic_pointer_cast<ConfigVar<T> >(it->second);
    }
    static void LoadFromYaml(YAML::Node &node);


    static ConfigVarbase:: ptr Lookupbase(const std::string &name);
private:
       static ConfigVarMap&   Getdatas(){
             static ConfigVarMap s_datas;
             return s_datas;
    } 
       static  MutexType& GetMutex(){
             static MutexType m_mutex;
             return m_mutex;
       }
 
    };

    
} // namespace Yizhi

#endif